<template>
  <div class="face_landmark_detection">
    <!-- 设置 -->
	<div class="option">
      <div>
        <label>更换图片</label>
		<input
          type="file"
          accept="image/png, image/jpeg"
          @change="fnChange($event)"
        />
      </div>
    </div>
	<!-- 图片 -->
    <div class="see">
      <img id="myImg" src="../../public/images/cp01.jpg" />
     <!-- 图形容器用于绘画 此处用于绘制检测人脸方框 -->
	  <canvas id="myCanvas" />
    </div>
  </div>
</template>

<script>
import * as faceapi from "face-api.js"; //导入face.api用于人脸识别
export default {
  name: "FaceLandmarkDetection",
  data() { //基本数据设置
    return {
		// Tiny Face Detector
		// Tiny Face Detector是一款性能非常高的实时人脸检测器，与SSD Mobilenet V1人脸检测器相比，它更快，更小，资源消耗更少，作为回报，它在检测小脸时的表现稍差。这个型号极具移动性和网络友好性，因此它应该是移动设备和资源有限的客户端上的GO-TO人脸检测器。量化模型的大小仅为190 KB（tiny_face_detector_model）。
		// SSD Mobilenet V1
		// 对于面部检测，该项目实现了基于MobileNetV1的SSD（单次多盒检测器）。神经网络将计算图像中每个面部的位置，并将返回边界框以及每个面部的概率。该面部检测器旨在获得检测面部边界框而不是低推理时间的高精度。量化模型的大小约为5.4 MB（ssd_mobilenetv1_model）。
		// MTCNN
		// MTCNN（多任务级联卷积神经网络）代表了SSD Mobilenet v1和Tiny Yolo v2的替代面部检测器，它提供了更多的配置空间。通过调整输入参数，MTCNN应该能够检测各种面部边界框大小。MTCNN是一个3级级联CNN，它同时返回5个面部标志点以及每个面的边界框和分数。此外，型号尺寸仅为2MB。
     
      options: null, // 模型参数
      imgEl: null,//用来放图片节点
      canvasEl: null,//用来放画板节点
    };
  },
  mounted() {
    //vue加载后  执行fn初始化方法  在初始化执行后 执行fnRun方法
	this.$nextTick(() => {
      this.fnInit().then(() => this.fnRun());
    });
  },
  methods: {
    // 初始化模型加载  async异步
    async fnInit() {
      await faceapi.nets.ssdMobilenetv1.loadFromUri("/models");//ssdMobilenetv1算法模型
      await faceapi.loadFaceLandmarkModel("/models");//轮廓模型
      // 根据模型参数识别调整结果
	  this.options = new faceapi.SsdMobilenetv1Options({
	    minConfidence: 0.5, // 0.1 ~ 0.9 //最小把握
	  });
      // 节点属性化
      this.imgEl = document.getElementById("myImg");
      this.canvasEl = document.getElementById("myCanvas");
    },
    // 执行识别绘制
    async fnRun() {
		//awaitawait即等待，用于等待一个Promise对象。
		//它只能在异步函数 async function中使用，否则会报错
      //检测人脸
	  const results = await faceapi.detectAllFaces(this.imgEl, this.options)
	  .withFaceLandmarks();////人脸特征（用来识别人脸）
      //我们希望将画布与其显示尺寸匹配，
	  //我们可以使用faceapi.matchDimensions(canvas，displaySize)来做到这一点
	  faceapi.matchDimensions(this.canvasEl, this.imgEl);
      // 创建一个调整大小的检测变量，
      //并将其设置为等于(faceapi.resizeResults(detections，displaySize)) ，
      //以便将框调整为我们的脸部大小
	  const resizedResults = faceapi.resizeResults(results, this.imgEl);
      //绘制人脸识别方框
	  faceapi.draw.drawDetections(this.canvasEl, resizedResults)
      //绘制人脸轮廓(我们使用绘制方框)/
	  //faceapi.draw.drawFaceLandmarks(this.canvasEl, resizedResults);
    },
    // 更换图片
    fnChange(e) {
      if (!e.target.files.length) return;
      // 将文件显示为图像并识别
      faceapi.bufferToImage(e.target.files[0]).then((img) => {
        this.imgEl.src = img.src;
        this.canvasEl
          .getContext("2d")
          .clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);
        this.fnRun();
      });
    },
  },
};
</script>

<style scoped>
.see {
  position: relative;
}
.see img {
  max-width: 600px;
  max-height: 400px;
}
.see canvas {
  position: absolute;
  top: 0;
  left: 0;
}
.option {
  padding-bottom: 20px;
}
.option div {
  padding: 10px;
  border-bottom: 2px #42b983 solid;
}
.option div label {
  margin-right: 20px;
}
</style>
